package shader;

import static org.lwjgl.opengl.GL20.glAttachShader;
import static org.lwjgl.opengl.GL20.glBindAttribLocation;
import static org.lwjgl.opengl.GL20.glCompileShader;
import static org.lwjgl.opengl.GL20.glCreateProgram;
import static org.lwjgl.opengl.GL20.glCreateShader;
import static org.lwjgl.opengl.GL20.glLinkProgram;
import static org.lwjgl.opengl.GL20.glShaderSource;

import java.io.File;

import ogl.app.FloatUniform;
import ogl.app.MatrixUniform;
import ogl.app.Util;
import ogl.app.VectorUniform;
import ogl.vecmath.Matrix;
import ogl.vecmath.Vector;

import org.lwjgl.opengl.GL20;

public class WavingFlagShader implements Shader {
	// The shader program
	private int program;
	
	private float currentTime;

	// The attribute indices for the vertex data.
	private static int vertexAttribIdx = 0;
	private static int colorAttribIdx = 1;
	private static int normalAttribIdx = 2;
	private static int textureAttribIdx = 3;

	// The location of the "mvpMatrix" uniform variable
	// (uniform because they don't change during the program runs)
	private MatrixUniform projectionMatrixUniform;
	private MatrixUniform modelMatrixUniform;
	private MatrixUniform viewMatrixUniform;
	
	private FloatUniform time;
	
	private VectorUniform lightPosition;
	
	// sources
	private int vs;
	private int fs;

	private String dir = System.getProperty("user.dir");

	/**
	 * Constructor for a default (Phong) shader
	 */
	public WavingFlagShader() {
		writeVertexShader(dir + "\\resources\\shader\\VertexShaderFlag.txt");
		writeFragmentShader(dir + "\\resources\\shader\\FragmentShaderFlag.txt");

		initShader();
	}
	
	/**
	 * Constructor for a custom shader.
	 * @param path to the VertexShader txt-file
	 * @param path to the FragmentShader txt-file
	 */
	public WavingFlagShader(String vertexPath, String fragmentPath) {
		writeVertexShader(vertexPath);
		writeFragmentShader(fragmentPath);

		initShader();
	}

	private void writeVertexShader(String path) {
		File v = new File(path);
		String[] vsSource = Util.fileToString(v);
		// Create and compile the vertex shader.
		vs = glCreateShader(GL20.GL_VERTEX_SHADER);
		glShaderSource(vs, vsSource);
		glCompileShader(vs);
		Util.checkCompilation(vs);
	}

	private void writeFragmentShader(String path) {
		File f = new File(path);
		String[] fsSource = Util.fileToString(f);
		// Create and compile the fragment shader.
		fs = glCreateShader(GL20.GL_FRAGMENT_SHADER);
		glShaderSource(fs, fsSource);
		glCompileShader(fs);
		Util.checkCompilation(fs);
	}
	
	private void initShader() {
		// Create the shader program and link vertex and fragment shader
		// together.
		program = glCreateProgram();
		glAttachShader(program, vs);
		glAttachShader(program, fs);

		// Bind the vertex attribute data locations for this shader program. The
		// shader expects to get vertex and color data from the mesh. This needs
		// to be done *before* linking the program.
		glBindAttribLocation(program, vertexAttribIdx, "vertex");
		glBindAttribLocation(program, colorAttribIdx, "color");
		glBindAttribLocation(program, normalAttribIdx, "normal");
		glBindAttribLocation(program, textureAttribIdx, "texCoords");

		// Link the shader program.
		glLinkProgram(program);
		Util.checkLinkage(program);

		// Bind the matrix uniforms to locations on this shader program. This
		// needs to be done *after* linking the program.
		// (in Klammern, 2ter Parameter -> Name der Matrix im Shader)
		projectionMatrixUniform = new MatrixUniform(program, "projectionMatrix");
		modelMatrixUniform = new MatrixUniform(program, "modelMatrix");
		viewMatrixUniform = new MatrixUniform(program, "viewMatrix");
		time = new FloatUniform(program, "time");
		lightPosition = new VectorUniform(program, "lightPosition");
	}

	public int getProgram() {
		return program;
	}

	public void setProjectionMatrixUniform(Matrix m) {
		projectionMatrixUniform.set(m);
	}

	public void setModelMatrixUniform(Matrix m) {
		modelMatrixUniform.set(m);
	}

	public void setViewMatrixUniform(Matrix m) {
		viewMatrixUniform.set(m);
	}
	
	public void addTime(float elapsed) {
		currentTime += elapsed;
		
		time.set(currentTime);
	}

	@Override
	public void setLightPosition(Vector position) {
		lightPosition.set(position);
	}
	
	@Override
	public void setAmbient(Vector ka) {}

	@Override
	public void setSpecular(Vector ks) {}

	@Override
	public void setShininess(float f) {}
	
	@Override
	public void setPhongParams(Vector ka, Vector ks, Float ke) {};

}
